"""
测试执行异步任务
使用Celery处理批量测试执行任务
"""

from celery import Celery, Task
from typing import List, Dict, Any, Optional
import os
import sys

# 添加项目根目录到Python路径
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(__file__))))

from app.services.executor import TestExecutor, DataDrivenExecutor
from app.services.data_source import DataSourceFactory
from app.services.report_generator import ReportGenerator
from app.models.test_result import TestResult
from app.models.report import Report
from app import db

# 配置Celery
celery_app = Celery(
    'smart_api_tester',
    broker=os.getenv('CELERY_BROKER_URL', 'redis://localhost:6379/0'),
    backend=os.getenv('CELERY_RESULT_BACKEND', 'redis://localhost:6379/0')
)

celery_app.conf.update(
    task_serializer='json',
    accept_content=['json'],
    result_serializer='json',
    timezone='Asia/Shanghai',
    enable_utc=True,
)


class DatabaseTask(Task):
    """支持数据库操作的Task基类"""
    _db = None

    @property
    def db_session(self):
        if self._db is None:
            from app import create_app
            app = create_app()
            self._db = app.app_context()
            self._db.push()
        return db


@celery_app.task(bind=True, base=DatabaseTask)
def execute_test_batch(self, task_config: Dict[str, Any]):
    """
    批量执行测试任务
    
    Args:
        task_config: 任务配置
            - project_id: 项目ID
            - project_name: 项目名称
            - base_url: 基础URL
            - test_cases: 测试用例列表
            - data_source_config: 数据源配置（可选）
            - report_id: 报告ID
    
    Returns:
        执行结果
    """
    try:
        # 更新任务状态
        self.update_state(state='PROGRESS', meta={'status': '初始化中...', 'progress': 0})
        
        project_id = task_config.get('project_id')
        project_name = task_config.get('project_name')
        base_url = task_config.get('base_url')
        test_cases = task_config.get('test_cases', [])
        data_source_config = task_config.get('data_source_config')
        report_id = task_config.get('report_id')
        
        # 创建执行器
        if data_source_config:
            # 数据驱动执行
            self.update_state(state='PROGRESS', meta={'status': '加载数据源...', 'progress': 10})
            
            data_source = DataSourceFactory.create(
                data_source_config['type'],
                data_source_config['config']
            )
            
            executor = DataDrivenExecutor(base_url)
            
            self.update_state(state='PROGRESS', meta={'status': '执行测试中...', 'progress': 20})
            
            results = executor.execute_with_data_source(test_cases, data_source)
        else:
            # 普通批量执行
            self.update_state(state='PROGRESS', meta={'status': '执行测试中...', 'progress': 20})
            
            executor = DataDrivenExecutor(base_url)
            results = executor.execute_batch(test_cases)
        
        # 保存测试结果到数据库
        self.update_state(state='PROGRESS', meta={'status': '保存结果...', 'progress': 70})
        
        for result in results:
            test_result = TestResult(
                case_id=result.get('case_id'),
                data_id=result.get('data_id'),
                execute_time=result.get('execute_time'),
                result=result.get('result'),
                response_time=result.get('response_time'),
                error_msg=result.get('error_msg'),
                request_detail=str(result.get('request_detail')),
                response_detail=str(result.get('response_detail')),
                report_id=report_id
            )
            self.db_session.session.add(test_result)
        
        self.db_session.session.commit()
        
        # 生成报告
        self.update_state(state='PROGRESS', meta={'status': '生成报告...', 'progress': 80})
        
        report_generator = ReportGenerator()
        report_data = report_generator.build_report_data(project_name, results)
        
        # 生成HTML报告
        reports_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'reports')
        os.makedirs(reports_dir, exist_ok=True)
        
        html_path = os.path.join(reports_dir, f'{report_id}.html')
        report_generator.generate_html_report(report_data, html_path)
        
        # 生成Excel报告
        excel_path = os.path.join(reports_dir, f'{report_id}.xlsx')
        report_generator.generate_excel_report(report_data, excel_path)
        
        # 更新报告记录
        report = Report.query.filter_by(report_id=report_id).first()
        if report:
            report.total_executions = len(results)
            report.success_count = sum(1 for r in results if r.get('result') == 'success')
            report.failed_count = len(results) - report.success_count
            report.pass_rate = (report.success_count / len(results) * 100) if results else 0
            report.html_path = html_path
            report.excel_path = excel_path
            self.db_session.session.commit()
        
        self.update_state(state='PROGRESS', meta={'status': '完成', 'progress': 100})
        
        return {
            'status': 'success',
            'report_id': report_id,
            'total': len(results),
            'success': sum(1 for r in results if r.get('result') == 'success'),
            'failed': sum(1 for r in results if r.get('result') == 'failed')
        }
        
    except Exception as e:
        self.update_state(state='FAILURE', meta={'status': f'执行失败: {str(e)}', 'progress': 0})
        raise


@celery_app.task
def cleanup_old_reports(days: int = 30):
    """
    清理旧报告任务
    
    Args:
        days: 保留天数
    """
    from datetime import datetime, timedelta
    from app.models.report import Report
    
    cutoff_date = datetime.now() - timedelta(days=days)
    
    old_reports = Report.query.filter(Report.generate_time < cutoff_date).all()
    
    for report in old_reports:
        # 删除报告文件
        if report.html_path and os.path.exists(report.html_path):
            os.remove(report.html_path)
        if report.pdf_path and os.path.exists(report.pdf_path):
            os.remove(report.pdf_path)
        if report.excel_path and os.path.exists(report.excel_path):
            os.remove(report.excel_path)
        
        # 删除数据库记录
        db.session.delete(report)
    
    db.session.commit()
    
    return f"已清理 {len(old_reports)} 个旧报告"
